﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ServiceModel.DomainServices.Client;
using Microsoft.Practices.Composite.Presentation.Commands;
using TelecoSystems.Infrastructure.Helpers;
using TelecoSystems.Infrastructure.Views;
using TelecoSystems.Web.Models;
using TelecoSystems.Web.Services.Customers;
using System.Collections.ObjectModel;
using TelecoSystems.Modules.Customers.Views;
using TelecoSystems.Modules.Customers.GeocodeService;
using Microsoft.Maps.MapControl;

namespace TelecoSystems.Modules.Customers.ViewModels {
    public class CustomersBrowseViewModel : PagedViewModelBase, INotifyPropertyChanged {
        #region Fields
        const string BING_MAPS_KEY = "AiiLAjhC0C8f6YSP1qqizKnD9m6scyDIyfaU4RpEbTnbs9jMPyxQmcQro7BvNjyr";
        CustomersDomainContext _customersCtx;
        #endregion

        #region Constructors
        public CustomersBrowseViewModel() {
            _countries = new LinkedList<Country>();
            _countries.Add(new Country() { Name = "Slovenská republika" });
            _countries.Add(new Country() { Name = "Česká republika" });
            NotifyPropertyChanged("Countries");
        }

        public CustomersBrowseViewModel(CustomersDomainContext customersCtx) {
            _customersCtx = customersCtx;

            Customers = new PagedEntityCollectionView<Customer>(_customersCtx.Customers, this);

            SubmitChangesCommand = new DelegateCommand<object>(SubmitChanges, CanSubmitChanges);
            AddCustomerPersonCommand = new DelegateCommand<object>(AddCustomerPerson, CanAddCustomerPerson);
            AddCustomerCompanyCommand = new DelegateCommand<object>(AddCustomerCompany, CanAddCustomerCompany);
            DeleteCustomerCommand = new DelegateCommand<object>(DeleteCustomer, CanDeleteCustomer);
            CancelCommand = new DelegateCommand<object>(Cancel, (o) => true);
            ShowLocationCommand = new DelegateCommand<object>(ShowLocation, CanShowLocation);

            LoadData();
        }
        #endregion

        public override void LoadData() {
            if (IsLoading || _customersCtx == null) {
                return;
            }

            IsBusy = true;
            IsLoading = true;

            _customersCtx.Customers.Clear();

            if (IsLoadingPeople) {
                var q = _customersCtx.GetPersonCustomersQuery();

                if (EmailFilter != "") {
                    q = q.Where(c => c.Email.Contains(EmailFilter));
                }
                if (NameFilter != "") {
                    q = q.Where(c => c.Name.Contains(NameFilter));
                }

                _customersCtx.Load(q, CustomersLoaded, null);
            } else if (IsLoadingCompanies) {
                var q = _customersCtx.GetCompanyCustomersQuery();

                _customersCtx.Load(q, CustomersLoaded, null);
            }
            /*if (Customers.SortDescriptions.Count > 0)
            {
                bool isFirst = true;
                foreach (SortDescription sd in Customers.SortDescriptions)
                {
                    q = OrderBy(q, isFirst, sd.PropertyName, sd.Direction == ListSortDirection.Descending);
                    isFirst = false;
                }
            }
            else
            {
                q = q.OrderBy(p => p.Id);
            }

            if (PageSize > 0)
            {
                q = q.Skip(PageSize * PageIndex);
                q = q.Take(PageSize);
            }*/
        }

        #region VM Properties
        public CustomersDomainContext DomainContext {
            get { return _customersCtx; }
        }
        #region Entity properties
        private ObservableCollection<Customer> _customersForFilter = new ObservableCollection<Customer>();
        public ObservableCollection<Customer> CustomersForFilter {
            get { return _customersForFilter; }
            set {
                _customersForFilter = value;
                NotifyPropertyChanged("CustomersForFilter");
            }
        }
        
        private PagedEntityCollectionView<Customer> _customers;
        public PagedEntityCollectionView<Customer> Customers {
            get {
                return _customers;
            }
            set {
                if (_customers != value) {
                    _customers = value;
                    NotifyPropertyChanged("Customers");
                }
            }
        }

        private Customer _customerDetail;
        public Customer CustomerDetail {
            get {
                return _customerDetail;
            }
            set {
                if (_customerDetail != value) {
                    _customerDetail = value;
                    NotifyPropertyChanged("CustomerDetail");
                    NotifyPropertyChanged("Customers");
                    if (DeleteCustomerCommand != null) DeleteCustomerCommand.RaiseCanExecuteChanged();

                    _customerDetail.PropertyChanged += (s, e) => {
                        if (SubmitChangesCommand != null)
                            SubmitChangesCommand.RaiseCanExecuteChanged();
                    };
                }
            }
        }
        #endregion

        private string _emailFilter = "";
        public string EmailFilter {
            get {
                return _emailFilter;
            }
            set {
                if (_emailFilter != value) {
                    _emailFilter = value;
                    NotifyPropertyChanged("EmailFilter");
                    LoadData();
                }
            }
        }

        private string _nameFilter = "";
        public string NameFilter {
            get {
                return _nameFilter;
            }
            set {
                if (_nameFilter != value) {
                    _nameFilter = value;
                    NotifyPropertyChanged("NameFilter");
                    
                    LoadData();
                }
            }
        }

        private bool _isBusy = false;
        public bool IsBusy {
            get { return _isBusy; }
            set {
                if (_isBusy != value) {
                    _isBusy = value;
                    NotifyPropertyChanged("IsBusy");
                }
            }
        }

        private bool _isLoadingPeople = true;
        public bool IsLoadingPeople {
            get {
                return _isLoadingPeople;
            }
            set {
                if (_isLoadingPeople != value) {
                    _isLoadingPeople = value;
                    NotifyPropertyChanged("IsLoadingPeople");
                    if (_isLoadingPeople) LoadData();
                }
            }
        }

        private bool _isLoadingCompanies = false;
        public bool IsLoadingCompanies {
            get { return _isLoadingCompanies; }
            set {
                if (_isLoadingCompanies != value) {
                    _isLoadingCompanies = value;
                    NotifyPropertyChanged("IsLoadingCompanies");
                    if (_isLoadingCompanies) LoadData();
                }
            }
        }

        private string _busyContent = "Please wait...";
        public string BusyContent {
            get { return _busyContent; }
            set {
                if (_busyContent != value) {
                    _busyContent = value;
                    NotifyPropertyChanged("BusyContent");
                }
            }
        }

        public class Country {
            public string Name { get; set; }
        }

        private ICollection<Country> _countries;
        public ICollection<Country> Countries {
            get {
                return _countries;
            }
            set {
                if (_countries != value) {
                    _countries = value;
                    NotifyPropertyChanged("Countries");
                }
            }
        }

        public string HeaderInfo { get { return "Browse Customers"; } }
        #endregion

        #region Commands
        public DelegateCommand<object> SubmitChangesCommand { get; set; }
        void SubmitChanges(object o) {
            IsBusy = true;
            _customersCtx.SubmitChanges(SubmitChangesCompleted, null);
        }
        bool CanSubmitChanges(object o) {
            return _customersCtx.HasChanges || ((CustomerDetail != null) ? CustomerDetail.HasChanges : false);
        }

        public DelegateCommand<object> AddCustomerPersonCommand { get; set; }
        void AddCustomerPerson(object o) {
            CustomerDetail = new CustomerPerson();
            DomainContext.Customers.Add(CustomerDetail);
        }
        bool CanAddCustomerPerson(object o) {
            return _customersCtx != null;
        }

        public DelegateCommand<object> AddCustomerCompanyCommand { get; set; }
        void AddCustomerCompany(object o) {
            CustomerDetail = new CustomerCompany();
            DomainContext.Customers.Add(CustomerDetail);
        }
        bool CanAddCustomerCompany(object o) {
            return _customersCtx != null;
        }

        public DelegateCommand<object> DeleteCustomerCommand { get; set; }
        void DeleteCustomer(object o) {
            Customers.Remove(CustomerDetail);
        }
        bool CanDeleteCustomer(object o) {
            return CustomerDetail != null;
        }

        public DelegateCommand<object> CancelCommand { get; set; }
        void Cancel(object o) {
            if (CustomerDetail.HasChanges) {
                ((IRevertibleChangeTracking)CustomerDetail).RejectChanges();
            }
        }

        public DelegateCommand<object> ShowLocationCommand { get; set; }
        void ShowLocation(object o) {
            GeocodeRequest geoReq = new GeocodeRequest();
            geoReq.Credentials = new Credentials();
            geoReq.Credentials.ApplicationId = BING_MAPS_KEY;

            geoReq.Query = CustomerDetail.AddressCity;

            ConfidenceFilter[] filters = new ConfidenceFilter[1];
            filters[0] = new ConfidenceFilter();
            filters[0].MinimumConfidence = GeocodeService.Confidence.High;

            GeocodeOptions geocodeOptions = new GeocodeOptions();
            geocodeOptions.Filters = filters;

            geoReq.Options = geocodeOptions;

            GeocodeServiceClient geocodeService = new GeocodeServiceClient("BasicHttpBinding_IGeocodeService");
            geocodeService.GeocodeCompleted += (s, e) => {
                GeocodeResponse geocodeResponse = e.Result;

                if (geocodeResponse.Results.Length > 0) {
                    double latitude = geocodeResponse.Results[0].Locations[0].Latitude;
                    double longtitude = geocodeResponse.Results[0].Locations[0].Longitude;

                    string address = string.Format("{0}, {1}", CustomerDetail.AddressStreet, CustomerDetail.AddressCity);
                    MapView view = new MapView(latitude, longtitude, CustomerDetail.Name, address);
                    view.Show();
                }
            };
            geocodeService.GeocodeAsync(geoReq);
        }
        bool CanShowLocation(object o) {
            return true;
        }
        #endregion

        #region Event Handlers
        private void CustomersLoaded(LoadOperation loadOperation) {
            if (loadOperation.HasError) {
                ErrorWindow.CreateNew(loadOperation.Error, StackTracePolicy.OnlyWhenDebuggingOrRunningLocally);
            } else {
                ItemCount = loadOperation.TotalEntityCount;
                TotalItemCount = loadOperation.TotalEntityCount;

                if (ItemCount > 0)
                    Customers.MoveCurrentToFirst();

                foreach(Customer cust in (IEnumerable<Customer>)Customers.SourceCollection) {
                    CustomersForFilter.Add(cust);
                }

                //InformationWindow.Create("Customers were loaded successfully.", "Notification");
            }
            IsLoading = false;
            IsBusy = false;
        }

        private void SubmitChangesCompleted(SubmitOperation submit) {
            if (submit.HasError) {
                foreach (Entity entity in submit.EntitiesInError) {

                }
                ErrorWindow.CreateNew(submit.Error, StackTracePolicy.OnlyWhenDebuggingOrRunningLocally);
            } else {
                InformationWindow.Create("Changes were saved successfully.", "Information");
            }
            IsBusy = false;
        }

        #endregion
    }
}
